﻿using System.Collections.Generic;

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Utilities.Tests
{
    [TestClass()]
    public class JsonSerializerTest
    {
        private TestContext testContextInstance;

        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion

        class Child
        {
            public string Name { get; set; }
            public int Age { get; set; }
            public string PreviousName { get; set; }
        }

        [TestMethod()]
        public void SerializePrimitiveTest()
        {
            Child girl = new Child
            {
                Name = "Sarah",
                Age = 10
            };

            string json = JsonSerializer.Serialize(girl);
            Assert.AreEqual(
@"{""Name"":""Sarah"",""Age"":10,""PreviousName"":null}", 
                json);

        }

        class ChildWithIgnoredAge
        {
            public string Name { get; set; }

            [JsonIgnore]
            public int Age { get; set; }

            public string PreviousName { get; set; }
        }

        [TestMethod()]
        public void SerializeIgnorePrimitiveTest()
        {
            ChildWithIgnoredAge girl = new ChildWithIgnoredAge
            {
                Name = "Sarah",
                Age = 10
            };

            string json = JsonSerializer.Serialize(girl);
            Assert.AreEqual(
@"{""Name"":""Sarah"",""PreviousName"":null}",
                json);

        }

        class Mother
        {
            public string Name { get; set; }
            public int Age { get; set; }
            public Child Girl { get; set; }
        }

        [TestMethod()]
        public void SerializeComplexTest()
        {
            Mother mother = new Mother
            {
                Name = "Yana",
                Age = 25,
                Girl = new Child
                {
                    Name = "Sarah",
                    Age = 10
                }
            };

            string json = JsonSerializer.Serialize(mother);
            Assert.AreEqual(
@"{""Name"":""Yana"",""Age"":25,""Girl"":{""Name"":""Sarah"",""Age"":10,""PreviousName"":null}}",
                json);

        }

        class MotherWithIgnoredAge
        {
            public string Name { get; set; }

            [JsonIgnore]
            public int Age { get; set; }

            public ChildWithIgnoredAge Girl { get; set; }
        }

        [TestMethod()]
        public void SerializeComplexWithIgnoreAttributeTest()
        {
            MotherWithIgnoredAge mother = new MotherWithIgnoredAge
            {
                Name = "Yana",
                Age = 25,
                Girl = new ChildWithIgnoredAge
                {
                    Name = "Sarah",
                    Age = 10
                }
            };

            string json = JsonSerializer.Serialize(mother);
            Assert.AreEqual(
@"{""Name"":""Yana"",""Girl"":{""Name"":""Sarah"",""PreviousName"":null}}",
                json);
        }

        class MotherWithIgnoredChild
        {
            public string Name { get; set; }

            public int Age { get; set; }

            [JsonIgnore]
            public Child Girl { get; set; }
        }

        [TestMethod()]
        public void SerializeComplexWithIgnoreComplexAttributeTest()
        {
            MotherWithIgnoredChild mother = new MotherWithIgnoredChild
            {
                Name = "Yana",
                Age = 25,
                Girl = new Child
                {
                    Name = "Sarah",
                    Age = 10
                }
            };

            string json = JsonSerializer.Serialize(mother);
            Assert.AreEqual(
@"{""Name"":""Yana"",""Age"":25}",
                json);
        }

        class MotherWithChildren
        {
            public string Name { get; set; }
            public int Age { get; set; }
            public IList<Child> Children { get; set; }
        }

        [TestMethod()]
        public void SerializeCollectionTest()
        {
            MotherWithChildren mother = new MotherWithChildren
            {
                Name = "Yana",
                Age = 25,
                Children = new List<Child>
                {
                    new Child
                    {
                        Name = "Sarah",
                        Age = 10
                    },
                    new Child
                    {
                        Name = "Mark",
                        Age = 20
                    }
                }
            };

            string json = JsonSerializer.Serialize(mother);
            Assert.AreEqual(
@"{""Name"":""Yana"",""Age"":25,""Children"":[{""Name"":""Sarah"",""Age"":10,""PreviousName"":null},{""Name"":""Mark"",""Age"":20,""PreviousName"":null}]}",
                json);

        }

        class Car
        {
            public enum Makes
            {
                Unknown = 0,
                Toyota,
                Honda,
                Hyundai
            }

            public Makes Make { get; set; }

            public string Model { get; set; }
        }

        [TestMethod()]
        public void SerializeEnumerationTest()
        {
            Car car = new Car
            {
                Make = Car.Makes.Hyundai,
                Model = "Tucson"
            };

            string json = JsonSerializer.Serialize(car);
            Assert.AreEqual(
@"{""Make"":3,""Model"":""Tucson""}",
                json);

        }

        [TestMethod()]
        public void SerializeListOfItemsWithEnumerationTest()
        {
            List<Car> cars = new List<Car>
            {
                new Car
                {
                    Make = Car.Makes.Hyundai,
                    Model = "Tucson"
                }
            };

            string json = JsonSerializer.Serialize(cars);
            Assert.AreEqual(
@"[{""Make"":3,""Model"":""Tucson""}]",
                json);

        }

        class MotherWithChildFirst
        {
            public Child Child { get; set; }

            public string Name { get; set; }

            public int Age { get; set; }
        }

        [TestMethod()]
        public void SerializeComplexWithInverseOrderTest()
        {
            MotherWithChildFirst mother = new MotherWithChildFirst
            {
                Name = "Yana",
                Age = 25,
                Child = new Child
                {
                    Name = "Sarah",
                    Age = 10
                }
            };

            string json = JsonSerializer.Serialize(mother);
            Assert.AreEqual(
@"{""Child"":{""Name"":""Sarah"",""Age"":10,""PreviousName"":null},""Name"":""Yana"",""Age"":25}",
                json);

        }

        class MotherWithChildSecond
        {
            public string Name { get; set; }

            public Child Child { get; set; }

            public int Age { get; set; }
        }

        [TestMethod()]
        public void SerializeComplexWithInverseOrderSecondTest()
        {
            MotherWithChildSecond mother = new MotherWithChildSecond
            {
                Name = "Yana",
                Age = 25,
                Child = new Child
                {
                    Name = "Sarah",
                    Age = 10
                }
            };

            string json = JsonSerializer.Serialize(mother);
            Assert.AreEqual(
@"{""Name"":""Yana"",""Child"":{""Name"":""Sarah"",""Age"":10,""PreviousName"":null},""Age"":25}",
                json);

        }

        class MotherWithBoyAndGirl
        {
            public string Name { get; set; }

            public Child Boy { get; set; }

            public Child Girl { get; set; }

            public int Age { get; set; }
        }

        [TestMethod()]
        public void SerializeComplexWithTwoComplexPropertiesTest()
        {
            MotherWithBoyAndGirl mother = new MotherWithBoyAndGirl
            {
                Name = "Yana",
                Age = 25,
                Girl = new Child
                {
                    Name = "Sarah",
                    Age = 10
                },
                Boy = new Child
                {
                    Name = "Mark",
                    Age = 20
                }
            };

            string json = JsonSerializer.Serialize(mother);
            Assert.AreEqual(
@"{""Name"":""Yana"",""Boy"":{""Name"":""Mark"",""Age"":20,""PreviousName"":null},""Girl"":{""Name"":""Sarah"",""Age"":10,""PreviousName"":null},""Age"":25}",
                json);

        }

        class MotherWithChildrenSecond
        {
            public string Name { get; set; }
            public IList<Child> Children { get; set; }
            public int Age { get; set; }       
        }

        [TestMethod()]
        public void SerializeCollectionAsSecondPropertyTest()
        {
            MotherWithChildrenSecond mother = new MotherWithChildrenSecond
            {
                Name = "Yana",
                Age = 25,
                Children = new List<Child>
                {
                    new Child
                    {
                        Name = "Sarah",
                        Age = 10
                    },
                    new Child
                    {
                        Name = "Mark",
                        Age = 20
                    }
                }
            };

            string json = JsonSerializer.Serialize(mother);
            Assert.AreEqual(
@"{""Name"":""Yana"",""Children"":[{""Name"":""Sarah"",""Age"":10,""PreviousName"":null},{""Name"":""Mark"",""Age"":20,""PreviousName"":null}],""Age"":25}",
                json);

        }

        [TestMethod()]
        public void SerializeListOfObjectsTest()
        {
            List<object> children = new List<object>
            {
                new { Name = "Mark", Age = 20 },
                new { Name = "Sarah", Age = 10 }
            };

            string json = JsonSerializer.Serialize(children);

            Assert.AreEqual(
@"[{""Name"":""Mark"",""Age"":20},{""Name"":""Sarah"",""Age"":10}]",
                json);

        }

        [TestMethod()]
        public void SerializeObjectWithListOfObjectsTest()
        {
            object mother = new 
            {
                Name = "Yana",
                Age = 25,
                Children = new List<object>
                {
                    new { Name = "Mark", Age = 20 },
                    new { Name = "Sarah", Age = 10 }
                }
            };

            string json = JsonSerializer.Serialize(mother);

            Assert.AreEqual(
@"{""Name"":""Yana"",""Age"":25,""Children"":[{""Name"":""Mark"",""Age"":20},{""Name"":""Sarah"",""Age"":10}]}",
                json);

        }
    }
}
